home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
dskutil
/
2m30src.zip
/
2MUTIL.INC
< prev
next >
Wrap
Text File
|
1995-03-06
|
38KB
|
995 lines
;┌───────────────────────────────────────────────────────────────────┐
;│ │
;│ █████ █ █ █ █ █████ █████ █ │
;│ █ ██ ██ █ █ █ █ █ │
;│ █████ █ █ █ █ █ █ █ █ │
;│ █ █ █ █ █ █ █ █ │
;│ █████ █ █ █████ █ █████ █████ │
;│ │
;│ 2MUTIL - (C) Ciriaco García de Celis. │
;│ │
;│ RUTINAS DE UTILIDAD EMPLEADAS DESDE DIVERSOS PROGRAMAS │
;│ │
;└───────────────────────────────────────────────────────────────────┘
; ------------ Extraer posibles parámetros de la línea de comandos.
; Formato de la tabla de parámetros soportados: cinco
; posibles modos, según el tipo de parámetro y la manera
; de validar el rango (si es numérico). Al final de la
; lista hay un 0. En minúsculas la parte opcional en
; parámetros largos.
;
; DB "/A",0 (caso sencillo)
; DW variable_booleana (a poner a ON u OFF)
; DB valor_booleano (ON u OFF)
;
; DB "/B",1
; DW min, max (caso de /B=nn ó /B:nn)
; DW variable_numérica (donde dejar nn)
; DW variable_booleana (a poner a ON u OFF)
; DB valor_booleano (ON u OFF)
;
; DB "/C",2
; DW numero_valores,valor1,valor2,...,valorN
; DW variable_numérica (donde dejar el valor)
; DW variable_booleana (a poner a ON u OFF)
; DB valor_booleano (ON u OFF)
;
; DB "*:",3 ( '*' = valor comodín)
; DB 'A' (restar a lo que sustituye)
; DB max_valor (mayor valor admitido)
; DW variable_dato (y poner aquí)
;
; DB "D",4 (parámetro alfanumérico)
; DW offset (offset al texto)
;
; DB 0 (no hay más parámetros)
obtener_param PROC
CALL param_mays ; mayusculizar parámetros
otro_pmt_mas: CALL saltar_esp ; saltar delimitadores
JNC otro_pmt ; quedan más parámetros
CMP param_ayuda,ON
JE mal_proc_pmt ; 'error' de ayuda
CLC ; parámetros bien procesados
RET
mal_proc_pmt: OR error,ERRSINTAX ; error en parámetro(s)
STC
RET
otro_pmt: CALL busca_pmt
JC mal_proc_pmt
CMP AL,1
JE pmt_numerico
CMP AL,2
JE pmt_numerico2
CMP AL,3
JE pmt_comodin
CMP AL,4
JE pmt_alfa
pmt_set: MOV SI,[DI]
MOV AL,[DI+2]
MOV [SI],AL
JMP otro_pmt_mas
pmt_numerico: CALL get_num
JC mal_proc_pmt
CMP AX,[DI]
JB mal_proc_pmt
CMP AX,[DI+2]
JA mal_proc_pmt
pmt_anota: MOV SI,[DI+4]
MOV [SI],AX
ADD DI,6
JMP pmt_set
pmt_numerico2: CALL get_num
JC mal_proc_pmt
MOV CX,[DI]
pmt_busca_r: ADD DI,2
MOV SI,[DI]
CMP AX,SI
JE pmt_rango_ok
LOOP pmt_busca_r
JMP mal_proc_pmt
pmt_rango_ok: ADD DI,2
LOOP pmt_rango_ok
SUB DI,4
JMP pmt_anota
pmt_comodin: MOV AL,ES:[BX-2]
SUB AL,[DI]
CMP AL,[DI+1]
JA mal_proc_pmt
MOV SI,[DI+2]
MOV [SI],AL
JMP otro_pmt_mas
pmt_alfa: MOV SI,[DI]
INC BX
MOV [SI],BX
saltar_asc: MOV AL,ES:[BX]
CMP AL,' '
JE fin_alfa
CMP AL,'/'
JE fin_alfa
CMP AL,13
JE fin_alfa
CMP AL,9
JE fin_alfa
INC BX
JMP saltar_asc
fin_alfa: JMP otro_pmt_mas
busca_pmt: MOV DI,BP
compara_pmt: MOV SI,BX
cmp_letra: MOV AL,[DI]
CMP AL,' '
JB pmt_ahi
CMP AL,'*'
JE pmt_ok
CMP AL,'a'
JAE pmt_comod
pmt_cmp: CMP AL,ES:[SI]
JNE no_pmt_ahi
JMP pmt_ok
pmt_comod: CMP BYTE PTR ES:[SI],' '
JBE pmt_sk
CMP BYTE PTR ES:[SI],'/'
JE pmt_sk
AND AL,255-32 ; mayusculizar
JMP pmt_cmp
pmt_ok: INC SI
pmt_sk: INC DI
JMP cmp_letra
pmt_ahi: INC DI ; DS:DI -> info, AL = tipo
MOV BX,SI ; ES:BX -> siguiente parámetro
CLC
RET
no_pmt_ahi: MOV AL,[DI]
CMP AL,' '
JB pmt_saltate
INC DI
JMP no_pmt_ahi
pmt_saltate: AND AL,AL
JZ pmt_salto0
CMP AL,1
JE pmt_salto1
CMP AL,2
JE pmt_salto2
CMP AL,4
JE pmt_salto4
ADD DI,5
JMP pmt_fintab?
pmt_salto0: ADD DI,4
JMP pmt_fintab?
pmt_salto1: ADD DI,10
JMP pmt_fintab?
pmt_salto4: ADD DI,3
JMP pmt_fintab?
pmt_salto2: MOV AX,[DI+1]
SHL AX,1
ADD AX,8
ADD DI,AX
pmt_fintab?: CMP BYTE PTR [DI],0
JE pmt_no_hay
JMP compara_pmt
pmt_no_hay: STC
RET
obtener_param ENDP
; ------------ Obtener número chequeando delimitadores /= y /:
get_num: MOV AL,ES:[BX]
INC BX
CMP AL,'='
JE delimit_ok
CMP AL,':'
JE delimit_ok
err_sintax: STC ; sintaxis incorrecta
RET
delimit_ok: MOV AL,ES:[BX]
XPUSH <SI, DI>
CALL obtener_num
XPOP <DI, SI>
JC err_sintax
INC BX
RET
; ------------ Extraer nº de 16 bits y depositarlo en AX; al final, el
; puntero (BX) apuntará al final del número y CF=1 si el
; número era incorrecto.
obtener_num PROC
CMP AL,0Dh ; fin zona parámetros y número
JE fin_num
CMP AL,32 ; fin número
JE fin_num
CMP AL,9 ; fin número
JE fin_num
CMP AL,'/' ; fin número (otro parámetro)
JE fin_num
CMP AL,':' ; fin número (otro dato)
JE fin_num
INC BX
MOV AL,ES:[BX]
JMP obtener_num
fin_num: MOV SI,BX
DEC SI
XOR DX,DX
MOV AX,1 ; AX = 10 elevado a la 0 = 1
otro_car: DEC BX ; próximo carácter a procesar
MOV CL,ES:[BX]
CMP CL,'='
JE ok_num ; delimitador: fin de número
CMP CL,':'
JE ok_num ; delimitador: fin de número
CMP CL,'.'
JNE no_millar ; saltar los puntos de millar
CMP AX,1000
JE otro_car
JMP mal_num ; separador millar descolocado
no_millar: CMP CL,'0'
JB mal_num
CMP CL,'9'
JA mal_num
SUB CL,'0' ; pasar ASCII a binario
MOV CH,0 ; CX = 0 .. 9
PUSH AX ; AX = 10 elevado a la N
AND AX,AX
JNZ multiplica
AND CL,CL
JNZ mal_num_pop ; a la izda sólo permitir ceros
multiplica: PUSH DX ; tras completar 5º dígito
MUL CX
POP DX
JC mal_num_pop
ADD DX,AX ; DX = DX + digito (CX) * 10 ^ N (AX)
JC mal_num_pop
POP AX
CMP AX,10000
JNE potencia ; AX*10 no se desbordará
MOV AX,0 ; como próximo dígito<>0 a
JMP otro_car ; la izda ... pobre usuario
potencia: MOV DI,10
PUSH DX ; no manchar DX al multiplicar
MUL DI ; AX = AX elevado a la (N+1)
POP DX
JMP otro_car
mal_num_pop: POP AX ; reequilibrar pila
mal_num: MOV BX,SI ; número mayor de 65535
STC ; condición de error
RET
ok_num: MOV BX,SI ; número correcto
MOV AX,DX ; resultado
CLC ; condición de Ok.
RET
obtener_num ENDP
; ------------ Poner en mayúsculas los nombres de los parámetros.
param_mays PROC
PUSH BX
otra_mays: MOV AL,ES:[BX]
CMP AL,13
JE mays_ret
CMP AL,':'
JE salta_valor
CMP AL,'='
JE salta_valor
JMP mays_mas
mays_ret: POP BX
RET
mays_mas: CMP AL,'a'
JB mayusc_ok
CMP AL,'z'
JA mayusc_ok
SUB AL,32
mayusc_ok: MOV ES:[BX],AL
INC BX
JMP otra_mays
salta_valor: INC BX
MOV AL,ES:[BX]
CMP AL,' '
JE otra_mays
CMP AL,9
JE otra_mays
CMP AL,'/'
JE otra_mays
CMP AL,13
JE otra_mays
JMP salta_valor
param_mays ENDP
; ------------ Saltar espacios, tabuladores,... buscando un parámetro.
saltar_esp: MOV AX,ES:[BX]
INC BX
CMP AL,9 ; carácter tabulador
JE saltar_esp
CMP AL,32 ; espacio en blanco
JE saltar_esp
CMP AL,0Ah ; fin de zona de parámetros
JE fin_param
CMP AL,0Dh ; fin de zona de parámetros
JE fin_param
DEC BX ; puntero al primer carácter
CLC ; hay parámetro
RET
fin_param: STC ; no hay parámetro
RET
; ------------ Comprobar si el programa ya reside en memoria. A la
; salida, CF=0 si programa ya reside, con «tsr_seg» y
; «tsr_off» inicializadas apuntando a la cadena de
; identificación de la copia residente. Si CF=1, el
; programa no reside aún (AX=0) o reside pero en otra
; versión distinta (AX=1).
residente? PROC
XPUSH <CX, SI, DI, ES, AX>
LEA DI,autor_nom_ver ; identificación del programa
MOV SI,DI
MOV AL,0
MOV CL,255
CLD
REPNE SCASB
SUB DI,SI
MOV CX,DI ; tamaño autor+programa+versión
MOV AX,1492h
MOV ES,AX
MOV DI,1992h ; ES:DI protocolo de búsqueda
CALL mx_find_tsr ; buscar si está en memoria
MOV tsr_off,DI ; anotar la dirección programa
MOV tsr_seg,ES ; por si estaba instalado
POP AX
JNC resid_ok ; CF=0 -> programa ya residente
POP ES
PUSH ES
LEA DI,autor_nom_ver
MOV SI,DI
MOV AL,':'
MOV CL,255
REPNE SCASB
REPNE SCASB
SUB DI,SI
MOV CX,DI ; tamaño autor+programa
MOV AX,1492h
MOV ES,AX
MOV DI,1992h ; ES:DI protocolo de búsqueda
CALL mx_find_tsr ; buscar si está en memoria
MOV tsr_off,DI ; anotar dirección del programa
MOV tsr_seg,ES ; por si instalada otra versión
MOV AX,0
JC resid_ok ; CF=1, AX=0 -> no residente
MOV AX,1
STC ; CF=1, AX=1 -> sí: otra vers.
resid_ok: XPOP <ES, DI, SI, CX>
RET
residente? ENDP
; ------------ Considerar presencia de controlador XMS.
inic_XMS PROC
PUSH ES
MOV AX,352Fh
INT 21h ; dirección de INT 2Fh en ES:BX
MOV AX,ES
POP ES
AND AX,AX
JZ xms_ausente ; apunta a 0000:XXXX (DOS 2.x)
MOV AX,4300h
INT 2Fh ; chequear presencia XMS
CMP AL,80h
JNE XMS_ausente ; no instalado
PUSH ES
MOV AX,4310h
INT 2Fh ; sí: obtener su dirección
MOV XMS_off,BX ; y preservarla
MOV XMS_seg,ES
MOV xms_ins,ON
POP ES
RET
XMS_ausente: MOV xms_ins,OFF
RET
inic_XMS ENDP
; ------------ Preservar vectores de interrupción previos.
preservar_INTs PROC
XPUSH <ES, DI>
LEA DI,tabla_vectores
MOV CL,[DI-1]
MOV CH,0 ; CX vectores interceptados
otro_vector: XPUSH <CX, DI>
MOV AH,35h
MOV AL,[DI]
INT 21h ; obtener vector de INT xx
XPOP <DI, CX>
MOV [DI+1],BX ; anotar donde apunta
MOV [DI+3],ES
ADD DI,5
LOOP otro_vector ; repetir con los restantes
XPOP <DI, ES>
RET
preservar_INTs ENDP
; ------------ Liberar espacio de entorno.
free_environ PROC
PUSH ES
MOV ES,DS:[2Ch] ; dirección del entorno
MOV AH,49h
INT 21h ; liberar espacio de entorno
POP ES
RET
free_environ ENDP
; ------------ Reservar bloque de memoria superior del nº párrafos AX,
; devolviendo en AX el segmento donde está. CF=1 si no
; está instalado el gestor XMS (AX=0) o hay un error (AL
; devuelve el código de error del controlador XMS).
UMB_alloc PROC
XPUSH <BX, CX, DX>
CMP xms_ins,ON
JNE no_umb_disp ; no hay controlador XMS
MOV DX,AX ; número de párrafos
MOV AH,10h ; solicitar memoria superior
CALL gestor_XMS
CMP AX,1 ; ¿ha ido todo bien?
MOV AX,BX ; segmento UMB/código de error
JNE XMS_fallo ; fallo
XPOP <DX, CX, BX> ; ok
CLC
RET
no_umb_disp: MOV AX,0
XMS_fallo: XPOP <DX, CX, BX>
STC
RET
UMB_alloc ENDP
; ------------ Reservar memoria superior, con DOS 5.0, del tamaño
; solicitado (AX párrafos). Si no hay bastante CF=1,
; en caso contrario devuelve el segmento en AX.
UPPER_alloc PROC
PUSH AX
MOV AH,30h
INT 21h
CMP AL,5
POP AX
JAE UPPER_existe
STC
JMP UPPER_fin ; necesario DOS 5.0 mínimo
UPPER_existe: PUSH AX ; preservar párrafos...
MOV AX,5800h
INT 21h
MOV alloc_strat,AX ; preservar estrategia
MOV AX,5802h
INT 21h
MOV umb_state,AL ; preservar estado UMB
MOV AX,5803h
MOV BX,1
INT 21h ; conectar cadena UMB's
MOV AX,5801h
MOV BX,41h
INT 21h ; High Memory best fit
POP BX ; ...párrafos requeridos
MOV AH,48h
INT 21h ; asignar memoria
PUSHF
PUSH AX ; guardado el resultado
MOV AX,5801h
MOV BX,alloc_strat
INT 21h ; restaurar estrategia
MOV AX,5803h
MOV BL,umb_state
XOR BH,BH
INT 21h ; restaurar estado cadena UMB
POP AX
POPF
upper_fin: RET
UPPER_alloc ENDP
; ------------ Manipular PID para independizar el bloque de memoria
; superior del programa y dejarlo residente. ES apunta
; al segmento y DS al PSP del programa principal.
upper_fork PROC
XPUSH <AX, CX, SI, DI, DS, ES>
MOV AX,ES
DEC AX
MOV ES,AX
INC AX
MOV WORD PTR ES:[1],AX ; manipular PID
MOV WORD PTR ES:[16],20CDh ; simular PSP
MOV AX,DS
DEC AX
MOV DS,AX
MOV CX,8
MOV SI,CX
MOV DI,CX
CLD
REP MOVSB ; copiar nombre de programa
XPOP <ES, DS, DI, SI, CX, AX>
RET
upper_fork ENDP
; ------------ Reubicar programa residente a su dirección definitiva.
; A la entrada, párrafos a mover en CX.
reubicar_prog PROC
PUSH DI
LEA SI,ini_residente
SHL CX,1
SHL CX,1
SHL CX,1
SHL CX,1
CLD
ADD SI,2 ; no copiar primera palabra
ADD DI,2 ; respetar primera palabra
SUB CX,2
REP MOVSB
POP DI
RET
reubicar_prog ENDP
; ------------ desviar vectores de interrupción a las nuevas rutinas.
; Se tendrá en cuenta que está ensambladas para correr en
; un offset inicial (100h) y que el offset real en que
; han sido instaladas está en DI. Por ello, CS ha de
; desplazarse (100h-DI)/16 unidades atrás (DI se supone
; múltiplo de 16). El segmento inicial es ES.
activar_INTs PROC
XPUSH <CX, DS> ; preservar DS para el retorno
MOV AX,100h
SUB AX,DI ; AX = 100h-DI
MOV CL,4
SHR AX,CL ; AX = (100h-DI)/16
MOV CX,ES
SUB CX,AX
MOV tsr_seg,CX
MOV DS,CX
LEA SI,offsets_ints
MOV CX,CS:[SI] ; CX vectores a desviar
ADD SI,2
desvia_otro: MOV AL,CS:[SI] ; número del vector en curso
MOV DX,CS:[SI+1] ; obtener offset
MOV AH,25h
INT 21h ; desviar INT xx a DS:DX
ADD SI,3
LOOP desvia_otro
XPOP <DS, CX>
RET
activar_INTs ENDP
; ------------ Buscar entrada no usada en la interrupción Multiplex.
; A la salida, CF=1 si no hay hueco (ya hay 64 programas
; residentes instalados con esta técnica). Si CF=0, se
; devuelve en AH un valor de entrada libre en la INT 2Fh.
mx_get_handle PROC
MOV AH,0C1h
mx_busca_hndl: PUSH AX
MOV AL,0
INT 2Fh
CMP AL,0FFh
POP AX
JNE mx_si_hueco
INC AH
JNZ mx_busca_hndl
STC
RET
mx_si_hueco: CLC
RET
mx_get_handle ENDP
; ------------ Buscar un TSR por la interrupción Multiplex. A la
; entrada, DS:SI cadena de identificación del programa
; (CX bytes) y ES:DI protocolo de búsqueda (normalmente
; 1492h:1992h). A la salida, si el TSR ya está instalado,
; CF=0 y ES:DI apunta a la cadena de identificación del
; mismo. Si no, CF=1 y ningún registro alterado.
mx_find_tsr PROC
MOV AH,0C1h
mx_rep_find: XPUSH <AX, CX, SI, DS, ES, DI>
MOV AL,0
PUSH CX
INT 2Fh
POP CX
CMP AL,0FFh
JNE mx_skip_hndl ; no hay TSR ahí
CLD
PUSH DI
REP CMPSB ; comparar identificación
POP DI
JE mx_tsr_found ; programa buscado hallado
mx_skip_hndl: XPOP <DI, ES, DS, SI, CX, AX>
INC AH
JNZ mx_rep_find
STC
RET
mx_tsr_found: ADD SP,4 ; «sacar» ES y DI de la pila
XPOP <DS, SI, CX, AX>
CLC
RET
mx_find_tsr ENDP
; ------------ Eliminar TSR del convenio si es posible. A la entrada,
; en AH se indica la entrada Multiplex; a la salida, CF=1
; si fue imposible y CF=0 si se pudo. Se corrompen todos
; los registros salvo los de segmento. En caso de fallo
; al desinstalar, AL devuelve el vector «culpable».
mx_unload PROC
PUSH ES
CALL mx_ul_tsrcv?
JNC mx_ul_able
POP ES
RET
mx_ul_able: XOR AL,AL
XCHG AH,AL
MOV BP,AX ; BP=entrada Multiplex del TSR
MOV CX,2
mx_ul_pasada: PUSH CX ; siguiente pasada
LEA SI,tabla_vectores
MOV CL,ES:[SI-1]
MOV CH,0 ; CX = nº vectores
mx_ul_masvect: POP AX
PUSH AX ; pasada en curso
DEC AL
PUSH CX
mx_ul_2f: MOV AL,ES:[SI] ; vector en curso
JNZ mx_ul_pasok
CMP CX,1 ; ¿último vector?
JNE mx_ul_noult
MOV AL,2Fh
LEA SI,tabla_vectores
mx_ul_busca2f: CMP ES:[SI],AL ; ¿INT 2Fh?
JE mx_ul_pasok
ADD SI,5
JMP mx_ul_busca2f
mx_ul_noult: CMP AL,2Fh ; ¿restaurar INT 2Fh?
JNE mx_ul_pasok
ADD SI,5
JMP mx_ul_2f
mx_ul_pasok: XPUSH <ES, AX>
MOV AH,0
SHL AX,1
SHL AX,1
DEC AX
MOV CS:mx_ul_tsroff,AX
MOV CS:mx_ul_tsrseg,0 ; apuntar a tabla vectores
POP AX
PUSH AX
MOV AH,35h
INT 21h ; vector en ES:BX
POP AX
MOV CL,4
SHR BX,CL
MOV DX,ES
ADD DX,BX ; INT xx en DX (aprox.)
MOV AH,0C1h
mx_ul_masmx: CALL mx_ul_tsrcv?
JNC mx_ul_tsrcv
JMP mx_ul_otro
mx_ul_tsrcv: PUSH ES:[DI-16] ; ...TSR del convenio en ES:DI
PUSH ES:[DI-12]
MOV DI,ES:[DI-8] ; offset a la tabla de vectores
MOV CL,ES:[DI-1]
MOV CH,0 ; número de vectores en CX
mx_ul_buscav: CMP AL,ES:[DI]
JE mx_ul_usavect ; este TSR usa vector analizado
ADD DI,5
LOOP mx_ul_buscav
ADD SP,4 ; no lo usa
JMP mx_ul_otro
mx_ul_usavect: XPOP <CX, BX> ; tamaño y segmento del TSR
CMP DX,BX
JB mx_ul_otro ; la INT xx no le apunta
ADD BX,CX
CMP DX,BX
JA mx_ul_otro ; la INT xx le apunta
PUSH AX
XOR AL,AL
XCHG AH,AL
CMP AX,BP ; ¿es el propio TSR?
POP AX
JNE mx_ul_chain ; no
XPOP <ES, CX, BX> ; sí: ¡posible reponer vector!
XPUSH <BX, CX, ES>
DEC BX
JNZ mx_ul_norest ; no es la segunda pasada
POP ES ; segunda pasada...
XPUSH <ES, DS>
MOV BX,CS:mx_ul_tsroff ; restaurar INT's
MOV DS,CS:mx_ul_tsrseg
CLI
MOV CX,ES:[SI+1]
MOV [BX+1],CX
MOV CX,ES:[SI+3]
MOV [BX+3],CX
STI
POP DS
mx_ul_norest: XPOP <ES, CX>
ADD SI,5 ; siguiente vector
DEC CX
JZ mx_unloadable ; no más, ¡desinstal-ar/ado!
JMP mx_ul_masvect
mx_ul_chain: MOV CS:mx_ul_tsroff,DI ; ES:DI almacena la dirección
MOV CS:mx_ul_tsrseg,ES ; de la variable vector
MOV DX,ES:[DI+1]
MOV CL,4
SHR DX,CL
MOV CX,ES:[DI+3]
ADD DX,CX ; INT xx en DX (aprox.)
MOV AH,0BFh
mx_ul_otro: INC AH ; a por otro TSR
JZ mx_ul_exitnok ; ¡se acabaron!
JMP mx_ul_masmx
mx_ul_exitnok: ADD SP,6 ; equilibrar pila
POP ES
STC
RET ; imposible desinstalar
mx_unloadable: POP CX
DEC CX
JZ mx_ul_exitok ; desinstalado
JMP mx_ul_pasada ; 1ª pasada exitosa: por la 2ª
mx_ul_exitok: TEST ES:info_extra,111b ; ¿tipo de instalación?
MOV ES,ES:segmento_real ; segmento real del bloque
JZ mx_ul_freeml ; cargado en RAM convencional
CMP xms_ins,ON
JNE mx_ul_freeml ; no hay controlador XMS (¿?)
MOV DX,ES
MOV AH,11h
CALL gestor_XMS ; liberar memoria superior
POP ES
CLC
RET
mx_ul_freeml: MOV AH,49h
INT 21h ; liberar bloque de memoria ES:
POP ES
CLC
RET
mx_ul_tsrcv?: XPUSH <AX, ES, DI> ; ¿es TSR del convenio?...
MOV DI,1492h
MOV ES,DI
MOV DI,1992h
INT 2Fh
CMP AX,0FFFFh
JNE mx_ul_ncvexit
CMP WORD PTR ES:[DI-4],"#*"
JNE mx_ul_ncvexit
CMP WORD PTR ES:[DI-2],"*#"
JNE mx_ul_ncvexit
ADD SP,4 ; CF=0
POP AX
RET
mx_ul_ncvexit: XPOP <DI, ES, AX> ; ...no es TSR del convenio
STC ; CF=1
RET
mx_ul_tsroff DW 0
mx_ul_tsrseg DW 0
mx_unload ENDP
; ------------ Devolver tipo de la unidad DL en BL, CF=1 si error.
; Se tiene especial cuidado con lo que devuelve la
; función (registros que modifica) y se reintenta porque
; algunas BIOS Award devuelven el error 6 (cambio de
; disco) al primer acceso, incluso ¡en esta función!.
tipo_disco PROC
XPUSH <AX, CX, DI, ES> ; *
MOV CX,3
busc_tipo: XPUSH <CX, DX> ; ** 3 reintentos
MOV AH,8
MOV BL,0
INT 13h
JC tipo_dsk_err
AND BL,BL
JZ tipo_dsk_err
AND DL,DL
JZ tipo_dsk_err
CMP BL,4
JBE tipo_dsk_ok
MOV BL,5 ; código 5 para 2.88M
tipo_dsk_ok: XPOP <DX, CX> ; **1
XPOP <ES, DI, CX, AX> ; *1
CLC
RET
tipo_dsk_err: XPOP <DX, CX> ; **2
LOOP busc_tipo
MOV BL,0
XPOP <ES, DI, CX, AX> ; *2
STC
RET
tipo_disco ENDP
; ------------ Establecer el tipo de las unidades a nivel DOS.
; A la entrada, DI apunta a la tabla de definiciones.
set_dev_params PROC
MOV AH,30h
INT 21h
XCHG AH,AL
CMP AX,314h
JB dev_set ; DOS < 3.2 -> no soportado
MOV BX,1
set_otro_dev: PUSH BX
MOV AH,8
MOV DL,BL
DEC DL
PUSH BX
PUSH ES
PUSH DI
INT 13h ; obtener tipo de la unidad
POP DI
POP ES
MOV BH,0
SHL BX,1
MOV DX,[BX+DI] ; DS:DX -> tabla de información
POP BX
AND DX,DX
JZ device_set
MOV AX,440Dh ; IOCTL
MOV CX,0840h
PUSH DI
INT 21h ; establecer tipo de soporte
POP DI
device_set: POP BX
INC BX
CMP BX,2
JBE set_otro_dev
dev_set: RET
set_dev_params ENDP
; ------------ Inicializar variable idioma_sp según idioma del país.
habla_hispana? PROC
XPUSH <AX, BX, CX, DX, BP>
MOV AH,30h
INT 21h
XCHG AH,AL ; AX = versión del DOS
MOV BP,AX
MOV idioma_sp,OFF ; supuesto de habla no hispana
CMP BP,200h
JB habla_ok
LEA DX,buffer_aux
MOV AX,3800h
INT 21h ; obtener información del pais
CMP BP,20Bh
JE habla_ax ; DOS 2.11: AX cód. telefónico
CMP BP,300h
JB habla_ok ; 2.x excepto 2.11: mala suerte
MOV AX,BX
habla_ax: LEA BX,paises_sp-2
MOV CX,numpaises_sp
habla_sp?: ADD BX,2
CMP AX,[BX]
JE habla_hispana
LOOP habla_sp?
habla_ok: MOV AL,param_i
XOR idioma_sp,AL ; considerar parámetro /I
XPOP <BP, DX, CX, BX, AX>
RET
habla_hispana: MOV idioma_sp,ON ; país de habla hispana
MOV AL,param_i
XOR idioma_sp,AL ; considerar parámetro /I
XPOP <BP, DX, CX, BX, AX>
RET
habla_hispana? ENDP
; ------------ Imprimir cadena en DS:DX delimitada por un 0 ó un 255.
; Si hay que imprimir en inglés se toma la cadena que va
; después si ésta acaba en 255 (si acaba en 0, no hay
; distinción entre mensaje castellano e inglés). El
; carácter de control 1 realiza una pausa hasta que se
; pulsa una tecla.
print PROC
XPUSH <AX, BX, CX, DX>
pr_decidir: CMP idioma_sp,OFF
JE usar_uk
CMP idioma_sp,ON
JE usar_sp
PUSH DX
CALL habla_hispana? ; determinar lengua
POP DX
JMP pr_decidir
usar_uk: MOV BX,DX
DEC BX
usar_uk?: INC BX
CMP BYTE PTR [BX],0
JE usar_sp ; acaba en 0: no traducir
CMP BYTE PTR [BX],255
JNE usar_uk?
LEA DX,[BX+1] ; acaba en 255: traducir
usar_sp: MOV BX,DX
DEC BX
print_cad: INC BX
CMP BYTE PTR [BX],0
JE prlong_ok
CMP BYTE PTR [BX],1 ; carácter de pausa
JE prpausa
CMP BYTE PTR [BX],255
JNE print_cad ; calcular longitud
JMP prlong_ok
prpausa: PUSH BX
MOV CX,BX
SUB CX,DX
MOV AH,40h
MOV BX,1
INT 21h ; imprimir hasta el código 1
pr_limpbuf: MOV AH,1
INT 16h
JZ pr_notec
MOV AH,0
INT 16h ; limpiar buffer del teclado
JMP pr_limpbuf
pr_notec: MOV AH,0
INT 16h ; esperar tecla
POP BX
INC BX
MOV DX,BX
CMP AL,27 ; ¿tecla ESC?
STC
JE pr_ret
JMP print_cad ; imprimir el resto
prlong_ok: MOV CX,BX
SUB CX,DX
MOV AH,40h
MOV BX,1
INT 21h
CLC
pr_ret: XPOP <DX, CX, BX, AX> ; CF = 1 si ESC durante pausa
RET
print ENDP
; ------------ Variables para estas subrutinas.
xms_ins DB OFF ; a ON si presente controlador XMS
gestor_XMS LABEL DWORD ; dirección del controlador XMS
XMS_off DW 0
XMS_seg DW 0
parrafos_resid DW ? ; párrafos de memoria consumidos
alloc_strat DW 0 ; estrategia asignación (DOS 5)
umb_state DB 0 ; estado de bloques UMB (DOS 5)
tsr_dir LABEL DWORD ; dirección de la copia residente
tsr_off DW 0
tsr_seg DW 0
mem640 DW 0 ; párrafos de memoria convencional
param_i DB OFF ; supuesto que no hay parámetro /I
idioma_sp DB 5Ah ; ni en ON ni en OFF al principio
; --- Código telefónico de países de
; habla hispana (mucha o poca).
paises_sp DW 54 ; Argentina
DW 591 ; Bolivia
DW 57 ; Colombia
DW 506 ; Costa Rica
DW 56 ; Chile
DW 593 ; Ecuador
DW 503 ; El Salvador
DW 34 ; España
DW 63 ; Filipinas
DW 502 ; Guatemala
DW 504 ; Honduras
DW 212 ; Marruecos
DW 52 ; México
DW 505 ; Nicaragua
DW 507 ; Panamá
DW 595 ; Paraguay
DW 51 ; Perú
DW 80 ; Puerto Rico
DW 508 ; República Dominicana
DW 598 ; Uruguay
DW 58 ; Venezuela
DW 3 ; genérico latinoamérica
numpaises_sp EQU ($-OFFSET paises_sp)/2